namespace FIREFLYX {
    /** 场景游戏对象（本身没有特定逻辑，承载组件） */
    export class GameObject implements IDispose, IInstanceID {
        //static
        /** GameObject 实例ID 记数*/
        private static _instanceIDCount: number = 0;
        /** 所有实体容器 */
        private static _GameObjectMap = new Map<number, GameObject>();
        /** 当实体创建 */
        private static _onGameObjectMake: Nullable<(e: GameObject) => void>;
        /** 当实体删除 */
        private static _onGameObjectDispose: Nullable<(e: GameObject) => void>;
        /** 当实体在层级中激活状态改变 */
        private static _onGameObjectActiveInHChange: Nullable<(e: GameObject) => void>;
        /** 当组件添加时 */
        private static _onComponentAdd: Nullable<(c: Component) => void>;
        /** 当组件移除时 */
        private static _onComponentRemove: Nullable<(c: Component) => void>;
        /** 需要调"Start()"的节点在 GameObject.List 中索引的列表 */
        public static readonly StartList: number[] = [];
        /** 需要调"Enable()"的节点在 GameObject.List 中索引的列表 */
        public static readonly EnableList: number[] = [];
        /** 需要调"Update()"的节点在 GameObject.List 中索引的列表 */
        public static readonly UpdateList: number[] = [];

        //public field
        public name: string;

        public get isDisposed() { return this._isDisposed; }

        //private field
        //被销毁？
        private _isDisposed: boolean = false;
        //实例ID
        private readonly _instanceID: number;
        //自身激活状态
        private _activeSelf: boolean = true;
        //在层级结构中的激活状态
        private _activeInHierarchy: boolean = true;

        //相同的组件只能加一个
        private _compsMap = new Map<string, Component>();
        private _compKeys: Nullable<string[]>;
        //灯光 类型名
        private _lightTypeName: string = "";
        //渲染器 类型名
        private _rendererTypeName: string = "";
        //相机 类型名
        private _cameraTypeName: string = "";

        //get set

        /** 通过 entity实例ID 获取实体  */
        public static getGameObject(entityInstID: number) {
            return this._GameObjectMap.get(entityInstID);
        }

        /** 组件数量 */
        public get componentCount() { return this._compsMap.size; }
        /** 自己是激活状态 */
        public get activeSelf() { return this._activeSelf; }
        /** 在节点层级中的激活状态 */
        public get activeInHierarchy() { return this._activeInHierarchy; }
        /** 获取transform组件 */
        public get transform() { return this._compsMap.get(Transform.name) as Transform; }
        /** 尝试获取灯光组件 */
        public get light() { return this._compsMap.get(this._lightTypeName) as Nullable<Light>; }
        /** 尝试获取渲染组件 */
        public get renderer() { return this._compsMap.get(this._rendererTypeName) as Nullable<Renderer>; }
        /** 尝试获取相机组件 */
        public get camera() { return this._compsMap.get(this._cameraTypeName) as Nullable<Camera>; }

        //fucntions

        /**
         * 初始化
         * @param onGameObjectMake 当场景添加 实体
         * @param onGameObjectDispose 当场景销毁 实体
         * @param onGameObjectActiveInHChange 当场景实体在层级激活状态发生变化
         * @param onComponentAdd 当场景添加 组件
         * @param onComponentRemove 当场景移除 组件
         */
        public static init(
            onGameObjectMake: (e: GameObject) => void,
            onGameObjectDispose: (e: GameObject) => void,
            onGameObjectActiveInHChange: (e: GameObject) => void,
            onComponentAdd: (c: Component) => void,
            onComponentRemove: (c: Component) => void,
        ) {
            //记录函数
            this._onGameObjectMake = onGameObjectMake;
            this._onGameObjectDispose = onGameObjectDispose;
            this._onGameObjectActiveInHChange = onGameObjectActiveInHChange;
            this._onComponentAdd = onComponentAdd;
            this._onComponentRemove = onComponentRemove;
        }

        /**
         * 场景节点对象构造
         * @param name 节点名
         */
        constructor(name: string = "") {
            this._instanceID = GameObject._instanceIDCount++;
            GameObject._GameObjectMap.set(this._instanceID, this);
            this.name = name;
            this.addComponent<Transform>(Transform);
            //创建回调
            if (GameObject._onGameObjectMake) GameObject._onGameObjectMake(this);
        }

        public getInstanceID(): number { return this._instanceID; }

        /**
         * 设置 实体激活状态
         * @param active 是否激活
         */
        public setActive(active: boolean) {
            this._activeSelf = active;
            //处理 子层级
            this.setActiveInHChildren(active);
        }

        public dispose(): void {
            if (this._compsMap) {
                let keys = Object.keys(this._compsMap);
                keys.forEach((val) => {
                    let comp = this._compsMap.get(val);
                    if (comp) {
                        comp.dispose();
                        this._compsMap.delete(val);
                    }
                });
            }

            (this._compsMap as any) = null;

            GameObject._GameObjectMap.delete(this._instanceID);
            //
            this._isDisposed = true;
            //销毁回调
            if (GameObject._onGameObjectDispose) GameObject._onGameObjectDispose(this);
        }

        /**
         * 添加组件
         * @param ctor 组件类
         * @returns 添加的组件
         */
        public addComponent<T extends Component>(ctor: typeof Component): Nullable<T> | never {
            let compTypeName = (ctor as any).name;
            if (compTypeName == Component.name) {
                console.warn(`Component "${compTypeName}" can't attach.`);
                return null;
            }
            if (this._compsMap.has(compTypeName)) {
                console.warn(`Component "${compTypeName}" attach fail , same Type Component can attach of only one.`);
                return null;
            }

            if (!this._compKeys) this._compKeys = [];
            this._compKeys.push(compTypeName);

            if (ctor.useSign != "none") {
                let needErr = true;
                switch (ctor.useSign) {
                    case "light":
                        if (!this._lightTypeName) {
                            this._lightTypeName = compTypeName;
                            needErr = false;
                        }
                        break;
                    case "renderer":
                        if (!this._rendererTypeName) {
                            this._rendererTypeName = compTypeName;
                            needErr = false;
                        }
                        break;
                    case "camera":
                        if (!this._rendererTypeName) {
                            this._rendererTypeName = compTypeName;
                            needErr = false;
                        }
                        break;
                    default:
                }

                if (needErr) {
                    console.warn(`Component "${compTypeName}" attach fail , same useSign Component can attach of only one.`);
                    return null;
                }
            }

            //实例化 组件
            let comp = new (ctor as any)();
            comp.entity = this;
            this._compsMap.set(compTypeName, comp);
            //组件添加回调
            if (GameObject._onComponentAdd) GameObject._onComponentAdd(comp);
            return comp as any;
        }

        /**
         * 移除组件
         * @param ctor 组件类
         */
        public removeComponent(ctor: typeof Component): void

        /**
         * 移除组件
         * @param comp 组件对象
         */
        public removeComponent(comp: Component): void
        public removeComponent(val: Component | (typeof Component)): void {
            if (!val) return;
            const _t: typeof Component = val instanceof (Component) ? Component : val;
            if (!_t || !_t.name) return;
            const _comp = this._compsMap.get(_t.name);
            if (!_comp) return;
            //清理标记
            switch (_t.useSign) {
                case "light": this._lightTypeName = ""; break;
                case "renderer": this._rendererTypeName = ""; break;
                case "camera": this._cameraTypeName = ""; break;
                default:
            }
            this._compsMap.delete(_t.name);
            if (GameObject._onComponentRemove) GameObject._onComponentRemove(_comp);
        }

        /** 移除所有组件 */
        public removeAllComponent() {
            const _map = this._compsMap;
            if (_map.size < 1) return;
            //
            this._lightTypeName = "";
            this._rendererTypeName = "";
            this._cameraTypeName = "";
            //
            let values: Nullable<Component[]> = null;
            if (GameObject._onComponentRemove) { values = Object.values(_map); }
            //清理容器
            _map.clear();
            this._compKeys = null;

            //回调触发
            if (GameObject._onComponentRemove) {
                const vals = values as Component[];
                for (let i = 0, len = vals.length; i < len; i++) {
                    const _comp = vals[i];
                    if (!_comp) continue;
                    GameObject._onComponentRemove(_comp);
                }
            }
        }

        /**
         * 获取组件
         * @param index 组件的索引 
         */
        public getComponent(index: number): Nullable<Component>
        /**
         * 获取组件
         * @param ctor 组件类对象
         * @returns 获取的组件
         */
        public getComponent<T extends Component>(ctor: typeof Component): Nullable<T>
        public getComponent<T extends Component>(val: typeof Component | number) {
            if (val == null) return null;
            let compK: string = "";
            if (typeof (val) !== "number") {
                compK = (val as any).name;
            } else {
                if (isNaN(val as number) || !this._compKeys || val < 0 || val >= this._compKeys.length) return null;
                compK = this._compKeys[val];
            }
            return this._compsMap.get(compK);
        }

        /**
         * 设置 所有层级子节点 实体激活状态
         * @param active 是否激活
         */
        private setActiveInHChildren(active: boolean) {
            const isChange = this._activeInHierarchy == active;
            this._activeInHierarchy = active;
            if (isChange && GameObject._onGameObjectActiveInHChange) {
                //激活状态变化回调
                GameObject._onGameObjectActiveInHChange(this);
            }
            const trans = this.transform;
            const cCount = trans.childCount;
            //传导到子节点
            for (let i = 0; i < cCount; i++) {
                const c = trans.getChild(i);
                if (!c) continue;
                const e = c.entity;
                if (!e) continue;
                if (active == false) {
                    if (e._activeInHierarchy == false) continue;   //该子节点已经标记过了
                } else {
                    if (e._activeSelf == e._activeInHierarchy) continue;  //该子节点不需要处理
                }
                e.setActiveInHChildren(active);
            }
        }
    }
}